package com.invengo.module_check.ui.fragment.netmodel;

import static me.goldze.mvvmhabit.bus._NetModel.OFFLINE;
import static me.goldze.mvvmhabit.bus._NetModel.ONLINE;

import android.app.Application;
import android.os.Handler;
import android.text.TextUtils;

import androidx.annotation.NonNull;
import androidx.databinding.ObservableBoolean;
import androidx.databinding.ObservableField;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.invengo.base.utils.CompressUtil;
import com.invengo.base.utils.ZipUtil;
import com.invengo.library_db.GreenDaoManager;
import com.invengo.library_db.entity.module_check.BookBean;
import com.invengo.library_db.entity.module_check.offline.BookJson;
import com.invengo.library_db.entity.module_check.ColumBean;
import com.invengo.library_db.entity.module_check.offline.FlowBean;
import com.invengo.library_db.entity.module_check.ShelfBean;
import com.invengo.library_db.entity.module_check.ShelfJson;
import com.invengo.library_db.entity.module_check.StructBean;
import com.invengo.library_db.utils.FileUtil;
import com.invengo.library_rfid.BuildConfig;
import com.invengo.module_check.data.repsitory.offlinedata.NetModelRepsitory;
import com.invengo.module_check.ui.fragment.netmodel.utils.DownloadSubscriber;
import com.invengo.module_check.ui.fragment.netmodel.utils.OfflineConformType;
import com.invengo.module_check.ui.fragment.netmodel.utils.RetryWithNewToken;

import org.reactivestreams.Subscription;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.TreeSet;
import java.util.stream.Collectors;

import io.reactivex.Flowable;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.ObservableSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import java8.util.stream.StreamSupport;
import me.goldze.mvvmhabit.base.BaseViewModel;
import me.goldze.mvvmhabit.binding.command.BindingCommand;
import me.goldze.mvvmhabit.bus.RxBus;
import me.goldze.mvvmhabit.bus.event.SingleLiveEvent;
import me.goldze.mvvmhabit.http.BaseBean;
import me.goldze.mvvmhabit.http.UpdateResult;
import me.goldze.mvvmhabit.http.interceptor.logging.LocalLogUtil;
import me.goldze.mvvmhabit.utils.KLog;
import me.goldze.mvvmhabit.utils.RxUtils;
import me.goldze.mvvmhabit.utils.StringUtils;
import me.goldze.mvvmhabit.utils.ToastUtils;
import me.goldze.mvvmhabit.utils.cache.ACache;
import me.goldze.mvvmhabit.utils.cache.AKey;
import me.goldze.mvvmhabit.utils.constant.Constants;
import me.jessyan.retrofiturlmanager.RetrofitUrlManager;
import okhttp3.HttpUrl;

public class NetModelViewModel extends BaseViewModel<NetModelRepsitory> {
    /**
     * 每页请求数量，
     */
//    总数据116万，20万每页 2.5分钟，10万每页 3.5分钟
    private static int PAGE_SIZE = 50000;
    /**
     * 弹窗配置参数args
     */
    public ObservableField<Object[]> args = new ObservableField<>(new Object[5]);

    public ObservableBoolean offlineModel = new ObservableBoolean(ACache.getInstance().getAsBoolean(AKey.IS_OFFLINE_MODEL));//离在线模式

    public ObservableBoolean openSelectShelf = new ObservableBoolean(ACache.getInstance().getAsBoolean(AKey.IS_OPEN_SELECT_SHELF));//是否开启层架选择
    public ObservableField<String> host = new ObservableField<>(ACache.getInstance().getAsString(AKey.CACHE_HOST));//请求地址
    public SingleLiveEvent<Boolean> syncDownBook = new SingleLiveEvent<>();   //异步处理开关
    public SingleLiveEvent<Boolean> selectCanOpen = new SingleLiveEvent<>();   //异步处理开关
    public SingleLiveEvent<Long> userCount = new SingleLiveEvent<>();//用户数据
    public SingleLiveEvent<String> layerValue = new SingleLiveEvent<>();//楼层数据
    public SingleLiveEvent<Long> layerCount = new SingleLiveEvent<>();//楼层数据
    public SingleLiveEvent<Long> bookCount = new SingleLiveEvent<>();//图书数据
    public SingleLiveEvent<String> dateTime = new SingleLiveEvent<>();//图书数据
    public SingleLiveEvent<Integer> businessCount = new SingleLiveEvent<>();//业务数据

    public NetModelViewModel(@NonNull Application application) {
        super(application, NetModelRepsitory.getInstance());
        loadDataFromDB();
    }

    /**
     * 从数据库加载数据
     */
    private void loadDataFromDB() {
        businessCount.postValue(model.getBusinessCountFromDB());
        syncDownBook.postValue(false);
        bookCount.postValue(model.getBookCountFromDB());
        userCount.postValue(model.getUserCountFromDB());
        setLayerCount(model.getShelfCountFromDB());
    }

    private void setLayerCount(long count) {
        layerCount.postValue(count);
        if (count > 10000) {
            layerValue.postValue(count / 10000 + "万架");
        } else if (count > 1000) {
            layerValue.postValue(count / 1000 + "千架");
        } else {
            layerValue.postValue(count + "架");
        }
        selectCanOpen.postValue(count != 0);
        if (count == 0)
            openSelectShelf.set(false);
    }

    public UIChangeObservable uc = new UIChangeObservable();

    public void changeDate(String date) {
        dateTime.postValue(date);
    }


    public class UIChangeObservable {
        public SingleLiveEvent<Boolean> downloadDialogEvent = new SingleLiveEvent<>();
        public SingleLiveEvent<Integer> downloadProgressEvent = new SingleLiveEvent<>();
        public SingleLiveEvent<String> downloadContentEvent = new SingleLiveEvent<>();
        public SingleLiveEvent<String> conformDialogEvent = new SingleLiveEvent<>();
        public SingleLiveEvent<String> dateDialogEvent = new SingleLiveEvent<>();
    }


    /**
     * @param isChecked
     */
    public void openAsyncCommand(boolean isChecked) {
        PAGE_SIZE = isChecked ? 150000 : PAGE_SIZE;
    }

    /**
     * @param isChecked
     */
    public void onSwitchCheckedChange(boolean isChecked) {
        ACache.getInstance().put(AKey.IS_OFFLINE_MODEL, isChecked);
        offlineModel.set(isChecked);
        RxBus.getDefault().post(isChecked ? OFFLINE : ONLINE);
    }

    public BindingCommand clickOpenSlectShelfCommand = new BindingCommand(() -> {
        if (!selectCanOpen.getValue()) {
            ToastUtils.showShort("请新下载层架数据");
        }
    });

    /**
     * @param isChecked
     */
    public void onOpenShelfSelect(boolean isChecked) {
        ACache.getInstance().put(AKey.IS_OPEN_SELECT_SHELF, isChecked);
        openSelectShelf.set(isChecked);
        if (isChecked && model.getAllColumCount() == 0) {
            analyzeShelf();
        }
    }

    public BindingCommand copyDB = new BindingCommand(() -> {
        String dbPath = "/data/data/com.invengo.module_check/databases/invengo-db";
        String dirPath = "/data/data/com.invengo.module_check/files/" + "invengo-db";
        ToastUtils.showShort("开始拷贝");
        Observable.just(dbPath)
                .subscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .doOnNext(s -> FileUtil.copyFile(dbPath, dirPath))
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(s -> ToastUtils.showShort("拷贝完成"));
    });


    /**
     * save config命令
     */
    public BindingCommand saveConfigCommand = new BindingCommand(() -> {
        if (!offlineModel.get()) {//如果在线模式，则直接跳转登录界面
            KLog.e(host.get());
            KLog.e(ACache.getInstance().getAsString(AKey.CACHE_HOST));
            KLog.e(host.get().equals(ACache.getInstance().getAsString(AKey.CACHE_HOST)));
            if (host.get().equals(ACache.getInstance().getAsString(AKey.CACHE_HOST))) {
                finish();
                return;
            }
            if (TextUtils.isEmpty(host.get())) {
                ToastUtils.showShort("API地址不能为空!");
                return;
            }
            HttpUrl parse = HttpUrl.parse(host.get());
            if (parse == null) {
                ToastUtils.showShort("请输入正确的地址!");
                host.set("");
                return;
            }
            KLog.e("执行了这一步。。。。");
            if (!checkEndswithNumber(host.get()) && !host.get().endsWith("/")) {
                host.set(host.get()+"/");
            }
            ACache.getInstance().put(AKey.CACHE_HOST, host.get());
            RetrofitUrlManager.getInstance().setGlobalDomain(host.get());
            finish();
        } else {//下载离线相关
            if (model.isHaveOfflineData()) {
                finish();
            } else {
                ToastUtils.showLong("尚未下载离线数据，请下载完成，否则将无法正常使用系统");
            }
        }
    });

    public boolean checkEndswithNumber(String str) {
        return str.matches(".*\\d$");
    }


    /**
     * 更新对话框
     *
     * @param content  所容纳之物
     * @param progress 进步
     */
    private double minProgress = 0;

    private void updateDialog(String content, double progress) {
        uc.downloadContentEvent.postValue(content);
        minProgress += progress;
        if (minProgress > 1) {
            double floor = Math.floor(minProgress);
            minProgress -= floor;
            uc.downloadProgressEvent.postValue((int) floor);
        }
    }

    /**
     * 清除业务数据
     */
    public BindingCommand handlerBusinessData = new BindingCommand(() -> {
        if (businessCount.getValue() != 0) {
            conformType = OfflineConformType.UPLOAD_BUSINESS_DATA;
            uc.conformDialogEvent.postValue("上传业务数据");
        } else {
            ToastUtils.showShort("无业务数据可以上传");
        }
    });

    /**
     * 清除所有数据
     */
    public BindingCommand cleanAllData = new BindingCommand(() -> {
        conformType = OfflineConformType.CLEAN_ALL_DATA;
        uc.conformDialogEvent.postValue("清除所有数据");
    });
    /**
     * 清除所有数据
     */
    public BindingCommand cleanBusinessData = new BindingCommand(() -> {
        conformType = OfflineConformType.CLEAN_BUSINESS_DATA;
        uc.conformDialogEvent.postValue("清除业务数据");
    });

    /**
     * 选择图书日期
     */
    public BindingCommand changeBookData = new BindingCommand(() -> {
        uc.dateDialogEvent.postValue(dateTime.getValue());
    });

    /**
     *  一键下载所有数据，比较麻烦，暂时不加
     */
    public BindingCommand downloadAllBaseData = new BindingCommand(() -> {
//        getAllUser();
//        getStructData();
//        getBookCount();
    });
    /**
     * 负载基础数据
     */
    public BindingCommand handlerUserData = new BindingCommand(() -> {
        if (userCount.getValue() == 0) {
            conformType = OfflineConformType.DOWN_USER_DATA;
            conformOpeartion();
        } else {
            conformType = OfflineConformType.CLEAN_USER_DATA;
            uc.conformDialogEvent.postValue("清除所有基础数据");
        }
    });
    /**
     * 负载基础数据
     */
    public BindingCommand handlerLayerData = new BindingCommand(() -> {
        if (layerCount.getValue() == 0) {
            conformType = OfflineConformType.DOWN_LAYER_DATA;
            conformOpeartion();
        } else {
            conformType = OfflineConformType.CLEAN_LAYER_DATA;
            uc.conformDialogEvent.postValue("清除书架数据");
        }
    });

    /**
     * 装载簿数据
     */
    public BindingCommand handlerBookData = new BindingCommand(() -> {
        if (bookCount.getValue() > 0) {
            conformType = OfflineConformType.CLEAN_BOOK_DATA;
            uc.conformDialogEvent.postValue("清除所有图书数据");
        } else {
            conformType = OfflineConformType.DOWN_BOOK_DATA;
            conformOpeartion();
        }
    });


    /**
     * 清除本地数据
     */


    private OfflineConformType conformType;

    /**
     * 一致操作
     */
    public void conformOpeartion() {
        Observable.just(conformType)
                .observeOn(AndroidSchedulers.mainThread())
                .doOnSubscribe(disposable -> {
                    showLoadingDialog("数据处理中..");
                })
                .subscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .doOnNext(type -> {
                    //子线程处理数据库删除操作
                    switch (type) {
                        case CLEAN_ALL_DATA:
                            model.cleanAllBaseData();
                            bookCount.postValue(0l);
                            userCount.postValue(0l);
                            setLayerCount(0l);

                            break;
                        case CLEAN_USER_DATA:
                            model.cleanUserData();
                            userCount.postValue(0l);
                            break;
                        case CLEAN_LAYER_DATA:
                            model.cleanLayerData();
                            setLayerCount(0l);
                            break;
                        case CLEAN_BOOK_DATA:
                            model.cleanBookData();
                            bookCount.postValue(0l);
                            break;
                        case CLEAN_BUSINESS_DATA:
                            model.cleanAllBusinessData();
                            businessCount.postValue(0);
                            break;
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(type -> {
                    dismissLodingDialog();
                    switch (type) {
                        case DOWN_USER_DATA:
                            getAllUser();
                            break;
                        case DOWN_LAYER_DATA:
//                            testShelf();


                            getAllShelf();

                            break;
                        case DOWN_BOOK_DATA:
                            getBookCount();
                            break;
                        case UPLOAD_BUSINESS_DATA:
                            uploadBusinessData();
                            break;
                        default:
                            ToastUtils.showShort("删除成功");
                            break;
                    }
                });

    }


    private void uploadBusinessData() {
        List<FlowBean> businessData = model.getBusinessData();
        Flowable.fromIterable(businessData)
                .subscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .doOnSubscribe(s -> businessFlowable = s)
                .map(bean -> {
                    tempFlowBean = bean;
                    return model.uploadData(bean);
                })
                .subscribe(new DownloadSubscriber<Observable<BaseBean<UpdateResult>>>() {
                    @Override
                    public void onNext(Observable<BaseBean<UpdateResult>> observable) {
                        doTask(observable);
                    }
                });
    }

    FlowBean tempFlowBean;
    public String userName = ACache.getInstance().getAsString(AKey.CACHE_USERNAME);
    //密码的绑定
    public String password = ACache.getInstance().getAsString(AKey.CACHE_PASSWORD);
    private void doTask(Observable<BaseBean<UpdateResult>> observable) {
        if (StringUtils.isEmpty(userName)|StringUtils.isEmpty(password)){
            ToastUtils.showShort("无法上传，没有默认账号信息");
            return;
        }
        observable
                .compose(RxUtils.applySchedulersIO(getLifecycleProvider(), NetModelViewModel.this))
                .subscribe(updateResult -> {
                    KLog.e("请求成功。。。");
                    model.deleteBusinessBean(tempFlowBean);
                    new Handler().postDelayed(() -> businessFlowable.request(1), 300);
                    businessCount.postValue(model.getBusinessCountFromDB());
                }, throwable -> {
                    new Handler().postDelayed(() -> businessFlowable.request(1), 300);
                    businessCount.postValue(model.getBusinessCountFromDB());
                });
    }

    /**
     * 获取所有用户
     */
    private void getAllUser() {
        model.getAllUser()
                .observeOn(AndroidSchedulers.mainThread())
                .doOnSubscribe(disposable -> {
                    uc.downloadDialogEvent.postValue(true);
                    updateDialog("用户数据下载..", 30);
                })
                .compose(RxUtils.applySchedulersIO(getLifecycleProvider(), this))
                .doOnNext(rfidUsers -> {
                    updateDialog("用户数据存储...", 70);
                    model.saveUser2DB(rfidUsers);
                    userCount.postValue(model.getUserCountFromDB());
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(rfidUsers -> uc.downloadDialogEvent.postValue(false));
    }

    private void testShelf() {
        Observable.just("李全民层标.json")
                .subscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .map(o -> {
                    KLog.e("11");
                    return readAsserts(o);
                })
                .map((Function<String, BaseBean<ShelfJson>>) s -> {
                    KLog.e("22");
                    return new Gson().fromJson(s, new TypeToken<BaseBean<ShelfJson>>() {
                    }.getType());
                })
                .map(shelfJsonBaseBean -> {
                    KLog.e("123");
                    return ZipUtil.GZipDecompressString(shelfJsonBaseBean.getData().getData());
//                    return CompressUtil.decompresss(shelfJsonBaseBean.getData().getData());
                })
                .map((Function<String, List<ShelfBean>>) json -> {
                    KLog.e("33");
                    return new Gson().fromJson(json, new TypeToken<List<ShelfBean>>() {
                    }.getType());
                })
                .doOnNext(shelfBeans -> {
                    KLog.e("44");
                    transShelfBean((List<ShelfBean>) shelfBeans);
                })
                .doOnNext(shelfBeans -> {
                    KLog.e("55");
                    transColums(shelfBeans);
                })
                .subscribe(shelfBeans -> KLog.e(shelfBeans.size() + "5455"),
                        throwable -> KLog.e(throwable.getMessage()));
    }

    private String readAsserts(String fileName) {
        String rel = "";
        try {
            InputStream is = getApplication().getAssets().open(fileName);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int len = -1;
            byte[] buffer = new byte[1024];
            while ((len = is.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }
            rel = baos.toString();
            KLog.e(rel);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return rel;
    }

    private void getAllShelf() {
        model.getStruct()
                .compose(RxUtils.applySchedulersLoading(getLifecycleProvider(), this))
                .retryWhen(new RxUtils.RetryWithTimeOut(2, 2000))
                .observeOn(AndroidSchedulers.mainThread())
                .doOnSubscribe(disposable -> {
                    uc.downloadDialogEvent.postValue(true);
                    updateDialog("楼层数据下载..", 10);
                })
                .observeOn(Schedulers.io())
                .doOnNext(structBeans -> {
                    updateDialog("清除楼层数据..", 10);
                    GreenDaoManager.getInstance().cleanAllStruct();
                })
                .doOnNext(structBeans -> {
                    updateDialog("楼层数据存储..", 10);
                    List<StructBean> collect = null;
                    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
                        collect = structBeans.stream().filter(structBean -> !TextUtils.isEmpty(structBean.getRoomName())).collect(Collectors.toList());
                    } else {
                        collect = StreamSupport.stream(structBeans).filter(structBean -> !TextUtils.isEmpty(structBean.getRoomName())).collect(java8.util.stream.Collectors.toList());
                    }
                    model.saveStruct2DB(collect);
                })
                .flatMap((Function<List<StructBean>, ObservableSource<BaseBean<ShelfJson>>>) structBeans -> {
                    updateDialog("获取层位数据..", 10);
                    return model.getAllShelf();
                })
                .map(shelfJsonBaseBean -> {
                    updateDialog("数据解密..", 10);
                    return shelfJsonBaseBean.getData();
                })
                .map(rfidDataDto -> {
                    updateDialog("数据解析..", 10);
                    return new Gson().fromJson(CompressUtil.decompresss(rfidDataDto.getData()), new TypeToken<List<ShelfBean>>() {
                    }.getType());
                })
                .map(shelfBeans -> {
                    updateDialog("数据转换..", 10);
                    return transShelfBean((List<ShelfBean>) shelfBeans);
                })
                .doOnNext(shelfBeans -> {
//                    List<ShelfBean> collect = StreamSupport.stream(shelfBeans).limit(900).collect(java8.util.stream.Collectors.toList());
//                    shelfBeans.stream().limit(1000)
                    model.insertSelfInfo(shelfBeans);
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(size -> {
                    setLayerCount(model.getShelfCountFromDB());
                    uc.downloadDialogEvent.postValue(false);
                }, throwable -> {
                    uc.downloadDialogEvent.postValue(false);
                    showDownLoadError(throwable);
                });

    }

    public void analyzeShelf() {
        Observable.just("1")
                .subscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .compose(RxUtils.bindToLifecycle(getLifecycleProvider()))
                .doOnSubscribe(tBaseBean -> {
                    getUC().getShowLoadingEvent().postValue("title");
                })
                .map(s -> model.getAllShelfFromDB())
                .doOnNext(shelfBeans -> {
                    model.removeAllColum();
                })
                .map(shelfBeans -> {
                    return transColums(shelfBeans);
                })
                .doOnNext(columBeans -> {
                    model.insertCoumBneas(columBeans);
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(size -> {
                    getUC().getDismissLoadingEvent().call();
                    ToastUtils.showShort("解析层架完成");
                }, throwable -> {
                    getUC().getDismissLoadingEvent().call();
                    ToastUtils.showShort("解析层架出现错误，请检查层位名是否符合规则");
                });
    }


    private List<ColumBean> transColums(List<ShelfBean> shelfBeans) {
//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//            return shelfBeans.stream().map(bean -> {
//                ColumBean columBean = new ColumBean();
//                columBean.setColumName(bean.getColumName());
//                columBean.setColumSortName(bean.getColumName().split("__")[1]);
//                columBean.setColumNum(Integer.parseInt(columBean.getColumSortName().replace("排", "").replace("架", "")));
//                return columBean;
//            }).collect(Collectors.collectingAndThen(
//                    Collectors.toCollection(() -> new TreeSet<>(
//                            Comparator.comparing(p -> p.getColumName()))), ArrayList::new));
//        } else {
        return StreamSupport.stream(shelfBeans).map(bean -> {
            ColumBean columBean = new ColumBean();
            columBean.setColumName(bean.getColumName());
            if (bean.getColumName().contains("__"))
                columBean.setColumSortName(bean.getColumName().split("__")[1]);
            try {
                columBean.setColumNum(Integer.parseInt(columBean.getColumSortName().replace("排", "").replace("架", "")));
            } catch (Exception e) {
                columBean.setColumNum(99999);
                LocalLogUtil.crash2Log(e.toString());
            }
            return columBean;
        }).collect(java8.util.stream.Collectors.collectingAndThen(
                java8.util.stream.Collectors.toCollection(() -> new TreeSet<>(
                        java8.util.Comparators.comparing(p -> p.getColumName()))), ArrayList::new));
//        }
    }

    private String getLayerName(ShelfBean bean) {
        String layerName = "";
        try {
            if (bean.getShelfName().isEmpty())
                return "未知";
            String replace = bean.getShelfName().replace(bean.getBuildingName(), "").replace(bean.getFloorName(), "").replace(bean.getRoomName(), "");
            if (replace.indexOf("架") > 0)
                layerName = replace.substring(0, replace.indexOf("架") + 1);
            if (TextUtils.isEmpty(layerName))
                if (replace.indexOf("排") > 0)
                    layerName = replace.substring(0, replace.indexOf("排") + 1);
        } catch (Exception e) {
            return "";
        }
        return layerName;
    }


    private List<ShelfBean> transShelfBean(List<ShelfBean> shelfBeans) {
        List<StructBean> allStruct = GreenDaoManager.getInstance().getAllStruct();
        return StreamSupport.stream(shelfBeans).map(shelfBean -> {
            int buildNo = Integer.parseInt(shelfBean.getShelfCode().substring(0, 2));
            int floorNo = Integer.parseInt(shelfBean.getShelfCode().substring(2, 4));
            int roomNo = Integer.parseInt(shelfBean.getShelfCode().substring(4, 6));
            StreamSupport.stream(allStruct).filter(it -> it.getBuildNo() == buildNo && floorNo == it.getFloorNo() && roomNo == it.getRoomNo()).findFirst().ifPresent(structBean -> {
                shelfBean.BuildNo = structBean.getBuildNo();
                shelfBean.FloorNo = structBean.getFloorNo();
                shelfBean.RoomNo = structBean.getRoomNo();
                shelfBean.BuildingName = structBean.getBuildingName();
                shelfBean.FloorName = structBean.getFloorName();
                shelfBean.RoomName = structBean.getRoomName();
                shelfBean.setColumName(structBean.getBuildingName() + structBean.getFloorName() + structBean.getRoomName() + "__" + getLayerName(shelfBean));
            });
            return shelfBean;
        }).collect(java8.util.stream.Collectors.toList());
    }


    /**
     * 获取书本数据
     */
    private void getBookCount() {
        waitForSave = false;
        model.getBookCount(dateTime.getValue(), null)
                .observeOn(AndroidSchedulers.mainThread())
                .doOnSubscribe(disposable -> uc.downloadDialogEvent.postValue(true))
                .compose(RxUtils.applySchedulersIO(getLifecycleProvider(), this))
                .subscribe(aLong -> {
                    if (aLong == 0) {
                        ToastUtils.showShort("当前没有可下载的图书！");
                        uc.downloadDialogEvent.postValue(false);
                    } else {
                        bookBackpressure(aLong);
                    }
                }, throwable -> {
                    uc.downloadDialogEvent.postValue(false);
                });
    }


    private Subscription subscription;
    private Subscription businessFlowable;
    private String downBookinfo = "(%d / %d )%s图书数据..\n共%s 每份%s";
    /**
     * 每份数据所占百分比
     */
    private float pencent = 0;
    private Flowable backpressureFlowable;

    /**
     * 书本背压
     * 控制发布者流速，防止数据存储压力过大
     *
     * @param booktotal 书籍计数
     */
    private void bookBackpressure(long booktotal) {
        model.cleanBookData();
        saveCount = 0;
        GreenDaoManager.getInstance().dropIndex();
        int pageTotal = (int) Math.ceil(Double.parseDouble(booktotal + "") / Double.parseDouble(PAGE_SIZE + ""));
        pencent = 100f / pageTotal;
        args.get()[0] = 0;
        args.get()[1] = pageTotal;
        args.get()[2] = "处理";
        args.get()[3] = getBookUnit(booktotal);
        args.get()[4] = getBookPrep(booktotal);
        List<Observable<BaseBean<String>>> observables = new ArrayList<>();
        Flowable.range(0, pageTotal)
                .observeOn(AndroidSchedulers.mainThread())
                .observeOn(Schedulers.io())
                .doOnSubscribe(s -> subscription = s)
                .subscribe(new DownloadSubscriber<Integer>() {
                    @Override
                    public void onNext(Integer integer) {
                        args.get()[0] = integer + 1;
                        Observable<BaseBean<BookJson>> pagingDataOfBook = model.getPagingDataOfBook(integer, PAGE_SIZE, null, null);
                        downloadByPage(pagingDataOfBook);
                    }
                });
    }


    public String getBookUnit(long booktotal) {
        if (booktotal >= 10000)
            return booktotal / 10000 + "万册";
        if (booktotal > 1000)
            return booktotal / 1000 + "千册";
        else
            return booktotal + "册";
    }

    public String getBookPrep(long booktotal) {
        if (booktotal >= PAGE_SIZE)
            return PAGE_SIZE / 10000 + "万册";
        else
            return booktotal + "册";
    }

    /**
     * 按页面下载
     */
    private void downloadByPage(Observable<BaseBean<BookJson>> observable) {
        args.get()[2] = "请求";
        long start = System.currentTimeMillis();
        updateDialog(String.format(downBookinfo, args.get()), pencent * 0.2);
        observable.retryWhen(new RxUtils.RetryWithTimeOut(3, 3000))
                .compose(RxUtils.applySchedulersIO(getLifecycleProvider(), this))
                .observeOn(Schedulers.io())
                .map(s -> {
                    args.get()[2] = "解析";
                    updateDialog(String.format(downBookinfo, args.get()), pencent * 0.3);
                    KLog.e("网络请求：" + (System.currentTimeMillis() - start) + "次数： " + args.get()[0]);
                    long start11 = System.currentTimeMillis();
                    List<BookBean> beans = new Gson().fromJson(CompressUtil.decompresss(s.getData()), new TypeToken<List<BookBean>>() {
                    }.getType());
                    KLog.e("数据转化：" + (System.currentTimeMillis() - start11) + "次数： " + args.get()[0]);
                    return beans;
                })
                .doOnNext(bookBeans -> {
                    args.get()[2] = "存储";
                    updateDialog(String.format(downBookinfo, args.get()), pencent * 0.5);
                    asyncSaveBookBean(bookBeans);
                })
                .subscribe(o -> {
                    if (args.get()[0] == args.get()[1]) {
                        waitForSave = true;
                    } else {
                        subscription.request(DownloadSubscriber.getRequestVlue());
                    }
                }, throwable -> {
                    uc.downloadDialogEvent.postValue(false);
                    showDownLoadError(throwable);
                });
    }

    private void showDownLoadError(Throwable throwable) {
        Observable.just(throwable.getMessage())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(s -> {
                    KLog.e("下载出现异常：" + throwable.getMessage() + " ,请检查网络及服务");
                    ToastUtils.showLong("下载出现异常：" + throwable.getMessage() + " ,请检查网络及服务");
                });

    }

    private boolean waitForSave = false;

    private int saveCount = 0;

    /**
     * 异步存储本bean
     *
     * @param bookBeans 书豆
     */
    private void asyncSaveBookBean(List<BookBean> bookBeans) {
        Observable.just(bookBeans)
                .subscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .subscribe(bookBeans1 -> {
                    long start = System.currentTimeMillis();
                    model.saveBooks2DB(bookBeans);
                    KLog.e("---存储时间： " + (System.currentTimeMillis() - start) + "  次数" + saveCount + "  " + (Integer) args.get()[1]);
                    saveCount++;
                    if (saveCount == (Integer) args.get()[1]) {
                        finishDownload();
                    }
                });
    }

    private void finishDownload() {
        args.get()[2] = "索引";
        updateDialog(String.format(downBookinfo, args.get()), pencent * 0.5);
        GreenDaoManager.getInstance().createNewIndex();
        bookCount.postValue(model.getBookCountFromDB());
        uc.downloadDialogEvent.postValue(false);
    }
}
